<?php

namespace App\Services;

use App\Common\Libs\ArrayHelper;
use App\Common\Libs\Dispatch\Console;
use App\Common\Libs\Dispatch\Queue;
use App\Console\Commands\Controller\RelationshipCommand;
use App\Consts\ExceptionCode;
use App\Consts\GlobalConsoleConst;
use App\Consts\GlobalCounterConst;
use App\Consts\GlobalQueueConst;
use App\Consts\GlobalRelationshipConst;
use App\Jobs\Controller\AttentionDynamicJob;
use App\Models\Cache\Cache;
use App\Models\Cache\CacheKey;
use App\Models\Field\UserField;
use App\Models\Select\UserSelect;
use App\Models\UserFollowingRelationship;
use Illuminate\Support\Facades\DB;

/**
 * @package App\Services
 * @see RelationshipService
 */
class RelationshipService extends BaseService
{

    /** @var $_repository */
    private $_repository;

    /**
     * RelationshipService constructor.
     */
    public function __construct()
    {
        parent::__construct();
        $this->_repository = repository()->RelationshipRepository;
    }

    /**
     * @param $params
     * @param $uid
     * @return mixed
     */
    public function onFollowing($params, $uid)
    {
        $userId = $params['user_id'] ?? 0;
        $searchParams = $params;
        $searchParams = ArrayHelper::merge($searchParams, [
            'user_id' => $uid ?: $userId,
            'current_user_id' => $params['current_user_id'],
            'attention_status' => [GlobalRelationshipConst::ATTENTION_STATUS_ATTENTION, GlobalRelationshipConst::ATTENTION_STATUS_EACH],
        ]);
        $relationshipList = $this->RelationshipService->getRelationshipList($searchParams);

        return $this->listResult($relationshipList);
    }

    /**
     * @param $params
     * @param $uid
     * @return mixed
     */
    public function onFollower($params, $uid)
    {
        $userId = $params['user_id'] ?? 0;
        $searchParams = $params;
        $searchParams = ArrayHelper::merge($searchParams, [
            'user_id' => $uid ?: $userId,
            'current_user_id' => $params['current_user_id'],
            'attention_status' => [GlobalRelationshipConst::ATTENTION_STATUS_FANS, GlobalRelationshipConst::ATTENTION_STATUS_EACH],
        ]);

        $relationshipList = $this->RelationshipService->getRelationshipList($searchParams);

        return $this->listResult($relationshipList);
    }

    /**
     * @param $params
     * @return array|\Illuminate\Http\JsonResponse|mixed
     */
    public function onAdd($params)
    {
        $followId = $params['follow_id'];
        $userId = $params['user_id'] ?? 0;
        if (!$followId) {
            return $this->throwError();
        }

        $currentUserId = $userId;
        if ($followId == $currentUserId) {
            return $this->operatingResult();
        }

        DB::beginTransaction();
        try {
            // 关注
            $attentionStatus = $this->RelationshipService->saveRelationship([
                'user_id' => $currentUserId,
                'follow_id' => $followId,
            ]);

            // 队列推送被关注者的动态
            Queue::getInstance(AttentionDynamicJob::class)
                ->push([
                    'user_id' => $userId,
                    'follow_id' => $followId,
                ], GlobalQueueConst::ATTENTION_PUSH);

            // 队列添加关注日志
            $this->RelationshipService->saveRelationshipLogCounterByQueue([
                'user_id' => $currentUserId,
                'follow_id' => $followId,
            ]);

            // 异步刷新用户关注数、粉丝数
            $this->RelationshipService->addToConsole(['user_id' => $currentUserId]);

            DB::commit();

            return $this->getResult([
                'attention_status' => $attentionStatus
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return $this->throwError(ExceptionCode::CODE_FAIL);
        }
    }

    /**
     * @param $params
     * @return array|\Illuminate\Http\JsonResponse|mixed
     */
    public function onCancel($params)
    {
        $userId = $params['user_id'] ?? 0;
        $followId = $params['follow_id'];
        if (!$followId) {
            return $this->throwError();
        }

        $currentUserId = $userId;
        if ($followId == $currentUserId) {
            return $this->operatingResult();
        }

        DB::beginTransaction();
        try {
            // 取消关注
            $attentionStatus = $this->RelationshipService->cancelRelationship([
                'user_id' => $currentUserId,
                'follow_id' => $followId,
            ]);
            if (!$attentionStatus) {
                return $this->throwError();
            }

            // 队列推送被关注者的动态
            Queue::getInstance(AttentionDynamicJob::class)
                ->push([
                    'user_id' => $currentUserId,
                    'follow_id' => $followId,
                ], GlobalQueueConst::ATTENTION_CANCEL_DEL);

            // 队列添加取消关注日志
            $this->RelationshipService->saveRelationshipLogCounterByQueue([
                'user_id' => $currentUserId,
                'follow_id' => $followId,
            ], true);

            // 异步刷新用户关注数、粉丝数
            $this->RelationshipService->addToConsole(['user_id' => $currentUserId]);

            DB::commit();

            return $this->getResult([
                'attention_status' => GlobalRelationshipConst::FRONTEND_STATUS_NULL
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return $this->throwError(ExceptionCode::CODE_FAIL);
        }
    }

    /**
     * 获取用户关注列表
     * @param array $searchParams
     * @return array
     */
    public function getRelationshipList($searchParams)
    {
        $dataProvider = $this->_repository->getRelationshipList($searchParams);
        $pagination = $this->getPagination();
        $relationships = $dataProvider->get();

        // 用户
        $userIdArr = array_unique(ArrayHelper::merge(ArrayHelper::getColumn($relationships, 'follow_id'), [$searchParams['current_user_id']]));
        $users = repository()->UserRepository
            ->getUserByUserIdArr($userIdArr, UserSelect::RELATIONSHIP);
        $users = ArrayHelper::index($users, 'user_id');

        $data = [];
        foreach ($relationships as $relationship) {
            $user = isset($users[$relationship->follow_id]) ? $users[$relationship->follow_id]->commonFormat(UserField::RELATIONSHIP) : [];
            $data[] = [
                'id' => $user['id'],
                'attention_status' => $this->getAttentionStatus($searchParams['current_user_id'], $user['id']),
                'created_at' => $relationship->created_at,
                'user' => $user,
            ];
        }

        return self::outputMoreList($dataProvider, $pagination, $data);
    }

    /**
     * 新增/更新关系
     * 注意
     *  1.代码中有注释，以A关注B为例。也可以看文档
     *  2.【关注关系】 0没关系，1user_id关注follow_id，3互相关注
     *  3.【粉丝关系】0没关系，2user_id是follow_id的粉丝，3互相关注
     * @param $params
     * @return bool|int
     */
    public function saveRelationship($params)
    {
        // 获取【当前用户】对【被关注人】的关系
        $attention = $this->_repository->getRelationshipById($params['user_id'], $params['follow_id']);

        // 【当前用户】对【被关注人】没有记录，说你【被关注人】对【当前用户】页一定没有记录
        //  新增【当前用户】对【被关注人】记录，attention_status = 1
        //  新增【被关注人】对【当前用户】记录，attention_status = 2
        if (!$attention) {
            $this->_repository->saveRelationship($params['user_id'], $params['follow_id'],
                GlobalRelationshipConst::ATTENTION_STATUS_ATTENTION);
            $this->_repository->saveRelationship($params['follow_id'], $params['user_id'],
                GlobalRelationshipConst::ATTENTION_STATUS_FANS);

            Cache::getInstance([
                'user_id' => $params['user_id']
            ])->incrFromArray(CacheKey::COUNTER_USER, GlobalCounterConst::COUNT_ATTENTION);

            Cache::getInstance([
                'user_id' => $params['follow_id']
            ])->incrFromArray(CacheKey::COUNTER_USER, GlobalCounterConst::COUNT_FANS);

            return GlobalRelationshipConst::FRONTEND_STATUS_ATTENTION;
        }

        // 【当前用户】已经关注叾【被关注人】 或  【当前用户】和【被关注人】互关，直接返回
        if ($attention->attention_status == GlobalRelationshipConst::ATTENTION_STATUS_ATTENTION ||
            $attention->attention_status == GlobalRelationshipConst::ATTENTION_STATUS_EACH) {
            return $attention->attention_status == GlobalRelationshipConst::ATTENTION_STATUS_ATTENTION ?
                GlobalRelationshipConst::FRONTEND_STATUS_ATTENTION : GlobalRelationshipConst::FRONTEND_STATUS_EACH;
        }

        // 【被关注人】已经关注了【当前用户】
        // 更新【被关注人】对【当前用户】记录，attention_status = 3
        // 更新【当前用户】对【被关注人】记录，attention_status = 3
        if ($attention->attention_status == GlobalRelationshipConst::ATTENTION_STATUS_FANS) {
            $this->_repository->saveRelationship($params['user_id'], $params['follow_id'],
                GlobalRelationshipConst::ATTENTION_STATUS_EACH);
            $this->_repository->saveRelationship($params['follow_id'], $params['user_id'],
                GlobalRelationshipConst::ATTENTION_STATUS_EACH);

            Cache::getInstance([
                'user_id' => $params['user_id'],
            ])->incrFromArray(CacheKey::COUNTER_USER, GlobalCounterConst::COUNT_ATTENTION);

            Cache::getInstance([
                'user_id' => $params['follow_id']
            ])->incrFromArray(CacheKey::COUNTER_USER, GlobalCounterConst::COUNT_FANS);

            return GlobalRelationshipConst::FRONTEND_STATUS_EACH;
        }

        $this->_repository->saveRelationship($params['user_id'], $params['follow_id'],
            GlobalRelationshipConst::ATTENTION_STATUS_ATTENTION);
        $this->_repository->saveRelationship($params['follow_id'], $params['user_id'],
            GlobalRelationshipConst::ATTENTION_STATUS_FANS);

        Cache::getInstance([
            'user_id' => $params['user_id']
        ])->incrFromArray(CacheKey::COUNTER_USER, GlobalCounterConst::COUNT_ATTENTION);

        Cache::getInstance([
            'user_id' => $params['follow_id']
        ])->incrFromArray(CacheKey::COUNTER_USER, GlobalCounterConst::COUNT_FANS);

        return GlobalRelationshipConst::FRONTEND_STATUS_ATTENTION;
    }

    /**
     * @param $params
     * @return bool|int
     */
    public function cancelRelationship($params)
    {
        // 获取【当前用户】对【被关注人】的关系
        $attention = $this->_repository->getRelationshipById($params['user_id'], $params['follow_id']);
        if (!$attention) {
            return false;
        }

        // 【当前用户】对【被关注人】没关系 attention_status = 0，
        //   或【被关注人】关注了【当前用户】但【当前用户】对【被关注人】没关系 attention = 2
        if ($attention->attention_status == GlobalRelationshipConst::ATTENTION_STATUS_NULL ||
            $attention->attention_status == GlobalRelationshipConst::ATTENTION_STATUS_FANS) {
            return GlobalRelationshipConst::FRONTEND_STATUS_NULL;
        }

        // 【当前用户】和【被关注人】互关
        if ($attention->attention_status == GlobalRelationshipConst::ATTENTION_STATUS_EACH) {
            $this->_repository->saveRelationship($params['user_id'], $params['follow_id'],
                GlobalRelationshipConst::ATTENTION_STATUS_FANS);
            $this->_repository->saveRelationship($params['follow_id'], $params['user_id'],
                GlobalRelationshipConst::ATTENTION_STATUS_ATTENTION);

            Cache::getInstance([
                'user_id' => $params['user_id']
            ])->incrFromArray(CacheKey::COUNTER_USER, GlobalCounterConst::COUNT_ATTENTION, GlobalCounterConst::DECREASE);

            Cache::getInstance([
                'user_id' => $params['follow_id']
            ])->incrFromArray(CacheKey::COUNTER_USER, GlobalCounterConst::COUNT_FANS, GlobalCounterConst::DECREASE);

            return GlobalRelationshipConst::FRONTEND_STATUS_NULL;
        }


        $this->_repository->saveRelationship($params['user_id'], $params['follow_id'],
            GlobalRelationshipConst::ATTENTION_STATUS_NULL);
        $this->_repository->saveRelationship($params['follow_id'], $params['user_id'],
            GlobalRelationshipConst::ATTENTION_STATUS_NULL);

        Cache::getInstance([
            'user_id' => $params['user_id']
        ])->incrFromArray(CacheKey::COUNTER_USER, GlobalCounterConst::COUNT_ATTENTION, GlobalCounterConst::DECREASE);

        Cache::getInstance([
            'user_id' => $params['follow_id']
        ])->incrFromArray(CacheKey::COUNTER_USER, GlobalCounterConst::COUNT_FANS, GlobalCounterConst::DECREASE);

        return GlobalRelationshipConst::FRONTEND_STATUS_NULL;
    }

    /**
     * 关注/取消关注后记录日志
     * @param $data
     * @param bool $isCancel
     * @return bool
     */
    public function saveRelationshipLogCounterByQueue($data, $isCancel = false)
    {
        $actionType = $isCancel ? GlobalCounterConst::ACTION_TYPE_CANCEL_ATTENTION : GlobalCounterConst::ACTION_TYPE_ATTENTION;

        $logData = [
            'send_user_id' => $data['user_id'],
            'receive_user_id' => $data['follow_id'],
            'action_id' => $data['user_id'],
            'action_type' => $actionType,
            'target_id' => '',
            'target_type' => 0,
            'created_at' => time(),
        ];

        $this->LogCountService->createLogByQueue($logData);
        return true;
    }

    /**
     * @param $userId
     * @param $followId
     * @return int
     */
    public function getAttentionStatus($userId, $followId)
    {
        if (!$userId) {
            return GlobalRelationshipConst::FRONTEND_STATUS_NULL;
        }

        if ($userId == $followId) {
            return GlobalRelationshipConst::FRONTEND_STATUS_MYSELF;
        }

        $relationship = $this->_repository->getRelationshipById($userId, $followId);
        if (!$relationship || $relationship->attention_status == GlobalRelationshipConst::ATTENTION_STATUS_FANS) {
            return GlobalRelationshipConst::FRONTEND_STATUS_NULL;
        }

        return GlobalRelationshipConst::$attentionStatusChange[$relationship->attention_status];
    }

    /**
     * @param $userId
     * @param $followId
     * @return int
     */
    public function getAttentionStatusByRelationship($relationships, $userId, $followId)
    {
        $relationships = ArrayHelper::index($relationships, 'user_id');
        if ($userId == $followId) {
            return GlobalRelationshipConst::FRONTEND_STATUS_MYSELF;
        }

        if (isset($relationships[$userId]['attention_status'])) {
            return GlobalRelationshipConst::$attentionStatusChange[$relationships[$userId]['attention_status']];
        }

        return GlobalRelationshipConst::FRONTEND_STATUS_NULL;
    }

    /**
     * 列表取值的时候，转换attention_status
     * @param $userId
     * @param $followId
     * @return array|UserFollowingRelationship[]
     */
    public function getRelationshipByIdArr($userId, $followId)
    {
        return $this->_repository->getRelationshipByIdArr($userId, $followId);
    }

    /**
     * 异步命令行 - 计数
     * @param $data
     */
    public function addToConsole($data)
    {
        Console::getInstance(RelationshipCommand::class)
            ->push($data, GlobalConsoleConst::RELATIONSHIP_COUNT);
    }
}
